package com.adui.mgt.performance.common;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * List匹配算法类
 *
 */
public abstract class ListMatch<T1, T2> {

	protected abstract Comparable<?>[] getKeys1(T1 item1);

	protected abstract Comparable<?>[] getKeys2(T2 item2);

	protected abstract void onOnlyItem1(T1 item1);

	protected abstract void onOnlyItem2(T2 item2);

	protected abstract void onMatched(T1 item1, T2 item2);

	private Comparator<T1> comparator1 = new Comparator<T1>() {
		public int compare(T1 a, T1 b) {
			return CompareUtil.compare(getKeys1(a), getKeys1(b));
		}
	};

	private Comparator<T2> comparator2 = new Comparator<T2>() {
		public int compare(T2 a, T2 b) {
			return CompareUtil.compare(getKeys2(a), getKeys2(b));
		}
	};

	/**
	 * List匹配
	 * @return [OnlyItem1的数量, OnlyItem2的数量, Matched的数量]
	 */
	public int[] match(List<T1> list1, List<T2> list2) {
		int count1 = 0;
		int count2 = 0;
		int countM = 0;
		list1 = list1 == null ? new ArrayList<>() : new ArrayList<>(list1);
		list2 = list2 == null ? new ArrayList<>() : new ArrayList<>(list2);
		Collections.sort(list1, comparator1);
		Collections.sort(list2, comparator2);
		int i = 0;
		int j = 0;
		while (i < list1.size() && j < list2.size()) {
			switch (CompareUtil.compare(getKeys1(list1.get(i)), getKeys2(list2.get(j)))) {
			case -1:
				onOnlyItem1(list1.get(i));
				i++;
				count1++;
				break;
			case 1:
				onOnlyItem2(list2.get(j));
				j++;
				count2++;
				break;
			default:
				int x = i + 1;
				int y = j + 1;
				for (; x < list1.size(); x++) {
					if (CompareUtil.compare(getKeys1(list1.get(i)), getKeys1(list1.get(x))) != 0) {
						break;
					}
				}
				for (; y < list2.size(); y++) {
					if (CompareUtil.compare(getKeys2(list2.get(j)), getKeys2(list2.get(y))) != 0) {
						break;
					}
				}
				for (; i < x; i++) {
					for (; j < y; j++) {
						onMatched(list1.get(i), list2.get(j));
						countM++;
					}
				}
				break;
			}
		}
		while (i < list1.size()) {
			T1 item1 = list1.get(i);
			onOnlyItem1(item1);
			i++;
			count1++;
		}
		while (j < list2.size()) {
			T2 item2 = list2.get(j);
			onOnlyItem2(item2);
			j++;
			count2++;
		}
		return new int[] { count1, count2, countM };
	}

}
